﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI;
using Number = GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.NumberValidation;
using Text = GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.TextValidation;
using Date = GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.DateValidation;

namespace GrayParrot.Web.Controls
{
    [Serializable]
    public abstract class QueryBuilderColumnFilter : ColumnFilter
    {
        public int Width { get; set; }
        public QueryBuilderDataTypes QueryBuilderDataType { get; set; }
        public QueryBuilderInputTypes QueryBuilderInputType { get; set; }
        internal new FilterTypes Type { get; set; }
        internal new string FilterContainerId { get; set; }
        internal new bool ShowResetButton { get; set; }
        
        public QueryBuilderColumnFilter()
        {
        }

        public QueryBuilderColumnFilter(QueryBuilderInputTypes type)
        {
            QueryBuilderInputType = type;
        }
    }

    [Serializable]
    public class QBTextColumnFilter : QueryBuilderColumnFilter
    {
        private new QueryBuilderDataTypes QueryBuilderDataType { get; set; }
        private new QueryBuilderInputTypes QueryBuilderInputType { get; set; }

        public string Format { get; set; }
        public int Min { get; set; }
        public int Max { get; set; }

        //[Browsable(false)]
        //[EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public ValidationSettings<Text.Validation> Validation { get; set; }

        public QBTextColumnFilter()
            : base(QueryBuilderInputTypes.Text)
        {
            Min = int.MinValue;
            Max = int.MinValue;
            Format = string.Empty;
        }

        public override string ToString()
        {
            string retValue = string.Empty;

            string m_data = string.Format("data: {{ width: '{0}' }}", this.Width);

            string m_validation = string.Empty;
            if (m_data.Count() > 0)
            {
                StringBuilder sb_validation = new StringBuilder();
                sb_validation.AppendLine(", validation: {");

                StringBuilder sb_messages = new StringBuilder();
                foreach (Text.Validation v in Validation.Settings)
                {
                    if ((!v.AllowEmpty) && (v.GetType() == typeof(GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.TextValidation.Min)))
                    {
                        sb_validation.AppendFormat("min: {0},\n", this.Min);

                        if (!string.IsNullOrWhiteSpace(v.Message))
                        {
                            sb_messages.AppendFormat("min: '{0}',\n", v.Message);
                        }
                    }

                    if ((!v.AllowEmpty) && (v.GetType() == typeof(GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.TextValidation.Max)))
                    {
                        sb_validation.AppendFormat("max: {0},\n", this.Max);

                        if (!string.IsNullOrWhiteSpace(v.Message))
                        {
                            sb_messages.AppendFormat("max: '{0}',\n", v.Message);
                        }
                    }

                    if ((!v.AllowEmpty) && (v.GetType() == typeof(GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.TextValidation.Format)))
                    {
                        sb_validation.AppendFormat("format: {0},\n", this.Format);

                        if (!string.IsNullOrWhiteSpace(v.Message))
                        {
                            sb_messages.AppendFormat("format: '{0}',\n", v.Message);
                        }
                    }
                }

                sb_validation.AppendFormat("messages: {{\n {0} }}\n", sb_messages.ToString());

                sb_validation.AppendLine("}");

                m_validation = sb_validation.ToString();
            }

            retValue = string.Format("{{ id: '{0}', label: '{1}', type: '{2}', {3} {4} }},",
                                         this.ColumnName,
                                         this.ColumnName,
                                         this.QueryBuilderDataType.ToString().ToLower(),
                                         m_data,
                                         m_validation
                                       );
            
            return retValue;
        }
    }

    public class QBTextAreaColumnFilter : QueryBuilderColumnFilter
    {
        private new QueryBuilderDataTypes QueryBuilderDataType { get; set; }
        private new QueryBuilderInputTypes QueryBuilderInputType { get; set; }

        public string Format { get; set; }
        public int Min { get; set; }
        public int Max { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public ValidationSettings<Text.Validation> Validation { get; set; }

        public QBTextAreaColumnFilter()
            : base(QueryBuilderInputTypes.Textarea)
        {
            Min = int.MinValue;
            Max = int.MinValue;
            Format = string.Empty;
        }

        public override string ToString()
        {
            string retValue = string.Empty;

            string m_data = string.Format("data: {{ width: '{0}' }}", this.Width);

            string m_validation = string.Empty;
            if (m_data.Count() > 0)
            {
                StringBuilder sb_validation = new StringBuilder();
                sb_validation.AppendLine(", validation: {");

                StringBuilder sb_messages = new StringBuilder();
                foreach (Text.Validation v in Validation.Settings)
                {
                    if ((!v.AllowEmpty) && (v.GetType() == typeof(GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.TextValidation.Min)))
                    {
                        sb_validation.AppendFormat("min: {0},\n", this.Min);

                        if (!string.IsNullOrWhiteSpace(v.Message))
                        {
                            sb_messages.AppendFormat("min: '{0}',\n", v.Message);
                        }
                    }

                    if ((!v.AllowEmpty) && (v.GetType() == typeof(GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.TextValidation.Max)))
                    {
                        sb_validation.AppendFormat("max: {0},\n", this.Max);

                        if (!string.IsNullOrWhiteSpace(v.Message))
                        {
                            sb_messages.AppendFormat("max: '{0}',\n", v.Message);
                        }
                    }

                    if ((!v.AllowEmpty) && (v.GetType() == typeof(GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.TextValidation.Format)))
                    {
                        sb_validation.AppendFormat("format: {0},\n", this.Format);

                        if (!string.IsNullOrWhiteSpace(v.Message))
                        {
                            sb_messages.AppendFormat("format: '{0}',\n", v.Message);
                        }
                    }
                }

                sb_validation.AppendFormat("messages: {{\n {0} }}\n", sb_messages.ToString());

                sb_validation.AppendLine("}");

                m_validation = sb_validation.ToString();
            }

            retValue = string.Format("{{ id: '{0}', label: '{1}', type: '{2}', {3} {4} }},",
                                         this.ColumnName,
                                         this.ColumnName,
                                         this.QueryBuilderDataType.ToString().ToLower(),
                                         m_data,
                                         m_validation
                                       );

            return retValue;
        }
    }

    [Serializable]
    public class QBNumberColumnFilter : QueryBuilderColumnFilter
    {
        private new QueryBuilderDataTypes QueryBuilderDataType { get; set; }
        private new QueryBuilderInputTypes QueryBuilderInputType { get; set; }

        public QueryBuilderNumberDataTypes NumberType { get; set; }
        public int Min { get; set; }
        public int Max { get; set; }
        public int Step { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public ValidationSettings<Number.Validation> Validation { get; set; }

        public QBNumberColumnFilter()
            : base(QueryBuilderInputTypes.Number)
        {
            Min = int.MinValue;
            Max = int.MinValue;
            Step = int.MinValue;
        }

        public override string ToString()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();
            sb.AppendLine("data: {");
            if (Min != int.MinValue)
            {
                sb.AppendFormat("min: {0},", Min);
            }
            if (Max != int.MinValue)
            {
                sb.AppendFormat("max: {0},", Max);
            }            //if (Step != int.MinValue)
            //{
            //    sb.AppendFormat("step: {0}", Step);
            //}

            sb.AppendLine("}");

            string m_data = string.Format("data: {{ width: '{0}' }}", this.Width);

            string m_validation = string.Empty;
            if (m_data.Count() > 0)
            {
                StringBuilder sb_validation = new StringBuilder();
                sb_validation.AppendLine(", validation: {");

                StringBuilder sb_messages = new StringBuilder();
                foreach (Number.Validation v in Validation.Settings)
                {
                    if ((!v.AllowEmpty) && (v.GetType() == typeof(GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.NumberValidation.Min)))
                    {
                        sb_validation.AppendFormat("min: {0},\n", this.Min);

                        if (!string.IsNullOrWhiteSpace(v.Message))
                        {
                            sb_messages.AppendFormat("min: '{0}',\n", v.Message);
                        }
                    }

                    if ((!v.AllowEmpty) && (v.GetType() == typeof(GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.NumberValidation.Max)))
                    {
                        sb_validation.AppendFormat("max: {0},\n", this.Max);

                        if (!string.IsNullOrWhiteSpace(v.Message))
                        {
                            sb_messages.AppendFormat("max: '{0}',\n", v.Message);
                        }
                    }

                    if ((!v.AllowEmpty) && (v.GetType() == typeof(GrayParrot.Web.Controls.Datatables.Filters.QueryBuilder.NumberValidation.Step)))
                    {
                        sb_validation.AppendFormat("step: {0},\n", this.Step);

                        if (!string.IsNullOrWhiteSpace(v.Message))
                        {
                            sb_messages.AppendFormat("step: '{0}',\n", v.Message);
                        }
                    }
                }

                sb_validation.AppendFormat("messages: {{\n {0} }}\n", sb_messages.ToString());

                sb_validation.AppendLine("}");

                m_validation = sb_validation.ToString();
            }

            retValue = string.Format("{{ id: '{0}', label: '{1}', type: '{2}', {3}, {4} {5} }},",
                 this.ColumnName,
                 this.ColumnName,
                 this.NumberType.ToString().ToLower(),
                 sb.ToString(),
                 m_data,
                 m_validation
               );

            return retValue;
        }
    }

    [Serializable]
    public class QBRadioColumnFilter : QueryBuilderColumnFilter
    {
        private new QueryBuilderDataTypes QueryBuilderDataType { get; set; }
        private new QueryBuilderInputTypes QueryBuilderInputType { get; set; }
        private List<ValidationBase> m_data = new List<ValidationBase>();

        public string Url { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public ValidationSettings<Number.Validation> Validation { get; set; }
        
        public QBRadioColumnFilter()
            : base(QueryBuilderInputTypes.Radio)
        {
        }

        public override string ToString()
        {
            string retValue = string.Empty;

            string m_data = string.Format("data: {{ url: '{0}' }}", this.Url);

            retValue = string.Format("{{ id: '{0}', label: '{1}', type: '{2}', input: '{3}', values: {{}}, {4} }},",
                 this.ColumnName,
                 this.ColumnName,
                 this.QueryBuilderDataType.ToString().ToLower(),
                 this.QueryBuilderInputType.ToString().ToLower(),
                 m_data
               );

            return retValue;
        }

    }

    [Serializable]
    public class QBCheckBoxColumnFilter : QueryBuilderColumnFilter
    {
        private new QueryBuilderDataTypes QueryBuilderDataType { get; set; }
        private new QueryBuilderInputTypes QueryBuilderInputType { get; set; }
        private List<ValidationBase> m_data = new List<ValidationBase>();
        public string Url { get; set; }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public List<ValidationBase> Validation
        {
            get
            {
                if (m_data == null)
                {
                    m_data = new List<ValidationBase>();
                }

                return m_data;
            }
            set { m_data = value; }
        }

        public QBCheckBoxColumnFilter()
            : base(QueryBuilderInputTypes.Checkbox)
        {
        }

        public override string ToString()
        {
            string retValue = string.Empty;

            string m_data = string.Format("data: {{ url: '{0}' }}", this.Url);

            retValue = string.Format("{{ id: '{0}', label: '{1}', type: '{2}', input: '{3}', values: {{}}, {4} }},",
                 this.ColumnName,
                 this.ColumnName,
                 this.QueryBuilderDataType.ToString().ToLower(),
                 this.QueryBuilderInputType.ToString().ToLower(),
                 m_data
               );

            return retValue;
        }
    }

    [Serializable]
    public class QBSelectColumnFilter : QueryBuilderColumnFilter
    {
        private new QueryBuilderDataTypes QueryBuilderDataType { get; set; }
        private new QueryBuilderInputTypes QueryBuilderInputType { get; set; }

        public Int16 MinQueryLength { get; set; }
        public bool Preload { get; set; }
        public string Url { get; set; }
        public string TextProp { get; set; }
        public string IDProp { get; set; }

        public QBSelectColumnFilter()
            : base(QueryBuilderInputTypes.Select)
        {
        }

        public override string ToString()
        {
            string retValue = string.Empty;

            string m_plugInCfg = string.Empty;

            StringBuilder sb = new StringBuilder();
            sb.AppendLine("plugin_config: {");
            sb.AppendFormat("  valueField: '{0}',\n", this.IDProp);
            sb.AppendFormat("  labelField: '{0}',\n", this.TextProp);
            sb.AppendFormat("  searchField: '{0}',\n", this.TextProp);
            sb.AppendFormat("  sortField: '{0}',\n", this.TextProp);
            sb.AppendLine("  preload: true,");
            sb.AppendLine("  create: false,");
            sb.AppendLine("  maxItems: 1,");
            sb.AppendLine("  plugins: ['remove_button'],");
            sb.AppendLine("  load: function(query, callback) {");
            sb.AppendFormat("       if (query.length < {0}) return callback();\n", this.MinQueryLength);
            sb.AppendLine("       $.ajax({");
            sb.AppendFormat("          url: '{0}',", this.Url);
            sb.AppendLine("          type: 'GET',");
            sb.AppendLine("          dataType: 'json',");
            sb.AppendLine("          error: function() {");
            sb.AppendLine("              callback();");
            sb.AppendLine("          },");
            sb.AppendLine("          success: function(res) {");
            sb.AppendLine("              callback(res);");
            sb.AppendLine("          }");
            sb.AppendLine("       });");
            sb.AppendLine("  }");
            sb.AppendLine("}");

            #region Example...
            //sb.AppendLine("  onInitialize: function() {");
            //sb.AppendLine("     var that = this;");
            //sb.AppendLine("     if (localStorage.demoData === undefined) {");
            //sb.AppendFormat("       data = {0}();", this.Callback);
            //sb.AppendLine("          localStorage.demoData = JSON.stringify(data);");
            //sb.AppendLine("          data.each(function(item) {");
            //sb.AppendLine("            that.addOption(item);");
            //sb.AppendLine("          });");
            //sb.AppendLine("     }");
            //sb.AppendLine("     else {");
            //sb.AppendLine("       JSON.parse(localStorage.demoData).each(function(item) {");
            //sb.AppendLine("         that.addOption(item);");
            //sb.AppendLine("       });");
            //sb.AppendLine("    }");
            //sb.AppendLine("  }");
            //sb.AppendLine("},");
            //sb.AppendLine("valueSetter: function(rule, value) {");
            //sb.AppendLine("  rule.$el.find('.rule-value-container input')[0].selectize.setValue(value);");
            //sb.AppendLine("}");
            #endregion

            m_plugInCfg = sb.ToString();

            string m_data = string.Format("data: {{ width: '{0}' }}", this.Width);

            retValue = string.Format("{{ id: '{0}', label: '{1}', type: '{2}', plugin:'selectize', {3}, {4} }},",
                             this.ColumnName,
                             this.ColumnName,
                             this.QueryBuilderDataType.ToString().ToLower(),
                             m_plugInCfg,
                             m_data
                           );


            return retValue;
        }
    }

    #region Example...
    /*
{
    id: 'category',
    label: 'Selectize',
    type: 'string',
    plugin: 'selectize',
    plugin_config: {
      valueField: 'id',
      labelField: 'name',
      searchField: 'name',
      sortField: 'name',
      create: true,
      maxItems: 1,
      plugins: ['remove_button'],
      onInitialize: function() {
        var that = this;

        if (localStorage.demoData === undefined) {
          $.getJSON(baseurl + '/assets/demo-data.json', function(data) {
            localStorage.demoData = JSON.stringify(data);
            data.forEach(function(item) {
              that.addOption(item);
            });
          });
        }
        else {
          JSON.parse(localStorage.demoData).forEach(function(item) {
            that.addOption(item);
          });
        }
      }
    },
    valueSetter: function(rule, value) {
      rule.$el.find('.rule-value-container input')[0].selectize.setValue(value);
    }
  }	     
     
     */
    #endregion

    [Serializable]
    public class QBDateTimeColumnFilter : QueryBuilderColumnFilter
    {
        private new QueryBuilderDataTypes QueryBuilderDataType { get; set; }
        private new QueryBuilderInputTypes QueryBuilderInputType { get; set; }
        private List<Date.Validation> m_data = new List<Date.Validation>();

        public bool ShowInLine { get; set; }
        public string DateFormat { get; set; }
        public QueryBuilderDateDataTypes DateDataType { get; set; }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public List<Date.Validation> Validation
        {
            get
            {
                if (m_data == null)
                {
                    m_data = new List<Date.Validation>();
                }

                return m_data;
            }
            set { m_data = value; }
        }

        public QBDateTimeColumnFilter()
            : base(QueryBuilderInputTypes.Date)
        {
        }

        public override string ToString()
        {
            string retValue = string.Empty;
            string m_plugInCfg = string.Empty;

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("validation: {");
            sb.AppendFormat("  format: '{0}'", this.DateFormat);
            sb.AppendLine("},");
            sb.AppendLine("plugin_config: {");
            sb.AppendLine("  viewMode: 'days',");
            sb.AppendLine("  showClose: true,");

            if (this.ShowInLine)
            {
                sb.AppendLine("  sideBySide: true,");
            }

            switch (this.DateDataType)
            {
                case QueryBuilderDateDataTypes.Date:
                    sb.AppendLine("  format: 'DD/MM/YYYY',");
                    break;
                case QueryBuilderDateDataTypes.Time:
                    sb.AppendLine("  format: 'HH:mm',");
                    break;
                case QueryBuilderDateDataTypes.Datetime:
                    sb.AppendFormat("  format: '{0}',", this.DateFormat);
                    break;
                default:
                    break;
            }
            
            sb.AppendLine("}");

            m_plugInCfg = sb.ToString();

            string m_data = string.Format("data: {{ width: '{0}' }}", this.Width);

            retValue = string.Format("{{ id: '{0}', label: '{1}', type: '{2}', plugin:'datetimepicker', {3}, {4} }},",
                 this.ColumnName,
                 this.ColumnName,
                 this.DateDataType.ToString().ToLower(),
                 m_plugInCfg,
                 m_data
               );

            return retValue;
        }
    }
}
